package com.cskaoyan.threadsafe.edition4;

import java.io.OutputStream;

/*
     如果，在不同synchronized代码块中，访问相同的共享变量，不同的代码块使用不同的锁对象，
     还是会存在多线程的数据安全问题：
     second售出了第94张票
     first售出了第94张票


      千万要注意：
         a. 虽然，synchronized代码块，中的锁对象，可以是java语言中的任意对象
         b. 但是，在多线程运行环境下，想要让访问 同一个共享变量的， 多个synchronized代码块中的代码是原子操作
            注意，对同一个共享变量的访问，必须使用同一个锁对象（加同一把锁）。


 */
public class Demo1 {

    public static void main(String[] args) {

        // 创建售票任务对象
        SalesTask salesTask = new SalesTask();

        Thread firstWindow = new Thread(salesTask, "first");
        Thread secondWindow = new Thread(salesTask, "second");
        Thread thirdWindow = new Thread(salesTask, "third");

        // 启动三个线程，模拟三个窗口售票
        firstWindow.start();
        secondWindow.start();
        thirdWindow.start();
    }
}


class SalesTask implements Runnable {

    //待售卖的100张票
    // 普通成员变量
    int tickets = 100;

    int i = 0;

    // 锁对象1
    private Object obj1 = new Object();

    // 锁对象2
    private Object obj2 = new Object();

    @Override
    public void run() {

        //  售卖100张票
        while (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (i % 2 == 0) {
                i++;
                synchronized (obj1) {
                    // 判断是否有票  double check
                    if (tickets > 0) {
                        System.out.println(Thread.currentThread().getName() + "售出了第" + tickets-- + "张票");
                    }
                }
            } else {
                i++;
                synchronized (obj1) {
                    // 判断是否有票  double check
                    if (tickets > 0) {
                        System.out.println(Thread.currentThread().getName() + "售出了第" + tickets-- + "张票");
                    }
                }
            }

        }
    }
}
